﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using DG.Common.EF.WPF;
using DG.Common.Patterns.Commands;
using DG.Common.Patterns.MVVM;
using TCC.ControleFluxoDeCaixa.Model.Contas;
using TCC.ControleFluxoDeCaixa.Model.Entities;
using TCC.ControleFluxoDeCaixa.Model.Fluxo;
using TCC.ControleFluxoDeCaixa.Model.Fluxo.Credito;

namespace TCC.ControleFluxoDeCaixa.Apresentacao.ViewModels
{
    public class LancamentoCadastroWindowViewModel : EntityCRUDViewModelBase<FluxoDeCaixaContextFiltrado, Lancamento>
    {
        private readonly ObservableCollection<Movimento> _movimentos = new ObservableCollection<Movimento>();

        public ObservableCollection<Movimento> Movimentos
        {
            get { return _movimentos; }
        }

        public IEnumerable<Categoria> ListaCategorias
        {
            get
            {
                return Context.Categorias.ToArray();
            }
        }
        public IEnumerable<ContaFinanceira> ListaContas
        {
            get
            {
                return Context.ContaFinanceiras.ToArray().Where(c=> !(c is ContaCredito))
                    .Union(Movimentos.Select(c=> c.Conta)).Where(c=> c != null)
                    .OrderBy(c=> c.Nome).Distinct().ToArray();
            }
        }

        protected override void BeforeSave()
        {
            base.BeforeSave();
            foreach (var movimento in Entity.Movimentos.Where(m => !Movimentos.Contains(m)).ToArray())
            {
                Entity.Movimentos.Remove(movimento);
                Context.Movimentos.Remove(movimento);
            }
            foreach (var movimento in Movimentos.Where(m => !Entity.Movimentos.Contains(m)).ToArray())
            {
                Entity.Movimentos.Add(movimento);
            }
        }

        protected override void AfterSetAction()
        {
            base.AfterSetAction();
            foreach (var i in Entity.Movimentos)
            {
                _movimentos.Add(i);
                i.PropertyChanged += (sender, args) => OnPropertyChanged("ValorTotal");
            }
                
            if (Action == CRUDOperationType.Create)
            {
                Entity.DataDoLancamento = DateTime.Now.Date;
                Entity.Usuario = Context.GetUsuarioLogado();
            }
        }

        
        public ICommand AdicionarMovimentoCommand
        {
            get
            {
                return new FunctionalCommand(() =>
                {
                    var movimento = new Movimento
                    {
                        Lancamento = Entity,
                        DataDoMovimento = DateTime.Now.Date,
                        TipoDeMovimento = TipoDeMovimento.Despesa
                    };
                    _movimentos.Add(movimento);

                    movimento.PropertyChanged += (sender, args) =>
                    {
                        OnPropertyChanged("ValorTotal");
                    };
                });
            }
        }
        public ICommand DeletarMovimentoCommand
        {
            get
            {
                return new FunctionalCommand((arg) =>
                {
                    var mov = arg as Movimento;
                    _movimentos.Remove(mov);
                });
            }
        }

        public LancamentoCadastroWindowViewModel()
        {
            Validator.AddMethodValidator(() => Movimentos.Any(), errorMessage:()=> "Lancamento Sem Movimentos Inseridos");
            Validator.AddMethodValidator(
                () => Movimentos.All(m => (int)m.TipoDeMovimento == 1 || (int)m.TipoDeMovimento == -1),
                errorMessage:()=> "Campo Tipo de Movimento Não Preenchido");

            _movimentos.CollectionChanged += (sender, args) =>
            {
                OnPropertyChanged("ValorTotal");
            };
        }

        public decimal ValorTotal
        {
            get
            {
                return Movimentos.Sum(m => m.Valor);
            }
        }
    }
}
